package com.fushenlan.epidemicControl.service.Impl;

import cn.hutool.json.JSONUtil;
import com.fushenlan.commons.GeneralResponse;
import com.fushenlan.enums.MarketCacheEnum;
import com.fushenlan.epidemicControl.service.IMarketCacheService;
import io.micrometer.core.instrument.util.StringUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.core.script.DefaultRedisScript;
import org.springframework.stereotype.Service;

import java.text.SimpleDateFormat;
import java.util.Collections;
import java.util.Date;
import java.util.concurrent.TimeUnit;

/**
 * @author PC
 * @title: MarketCacheServiceImpl
 * @projectName SpringBootDemo
 * @description: redis缓存工具类
 * @date 2022/1/21 9:41
 */
@Slf4j
@Service
public class MarketCacheServiceImpl implements IMarketCacheService {

    @Autowired
    private StringRedisTemplate stringRedisTemplate;

    public static final String CACHE_SPLIT = ":";
    private static final String CACHE_FLAG = "MarketCache";

    private String cacheFlagKey() {
        return CACHE_FLAG;
    }

    private String cacheFlag() {
        Object res = stringRedisTemplate.opsForValue().get(cacheFlagKey());
        if (res != null) {
            return String.valueOf(res);
        }
        SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd");
        String dateNow = simpleDateFormat.format(new Date());
        String cacheFlag = CACHE_FLAG + dateNow;
        log.info("MarketCacheServiceImpl.cacheFlag() " + cacheFlag);
        stringRedisTemplate.opsForValue().set(cacheFlagKey(), cacheFlag, 10800L, TimeUnit.SECONDS);
        return cacheFlag;
    }

    private String assembleCacheKey(MarketCacheEnum keyPrefix, String key) {
        return new StringBuffer(cacheFlag()).append(CACHE_SPLIT)
                .append(keyPrefix.toString()).append(cacheFlag())
                .append(key).toString();

    }

    @Override
    public Object getCache(MarketCacheEnum keyPrefix, String key) {
        String cacheKey = assembleCacheKey(keyPrefix, key);
        Object res = stringRedisTemplate.opsForValue().get(cacheKey);
        if (res != null) {
            log.info("======>从缓存中获取结果，缓存 key = {}", cacheKey);
        }
        return res;
    }

    @Override
    public void cacheResponse(MarketCacheEnum keyPrefix, String key, Object response, long cacheSeconds) {
        try {
            GeneralResponse generalResponse = (GeneralResponse) response;
            if (generalResponse != null && GeneralResponse.CODE_SUCCESS.equals(generalResponse.getCode())) {
                String cacheKey = assembleCacheKey(keyPrefix, key);
                stringRedisTemplate.opsForValue().set(cacheKey, JSONUtil.toJsonStr(response), cacheSeconds, TimeUnit.SECONDS);
            }
        } catch (Exception e) {
            log.error("IMarketCacheService.cacheResponse() failed!", e);
        }
    }

    @Override
    public void refreshAllCache() {
        String luaScript1 = "" +
                "local function scan(key)\n" +
                "  local cursor = 0\n" +
                "  local keynum = 0\n" +
                "  local delNum = 0\n" +
                "\n" +
                "  repeat\n" +
                "       local res = redis.call('scan', cursor, 'MATCH', key, 'COUNT', ARGV[1])\n" +
                "\n" +
                "       if (res ~= nil and #res >=0) then\n " +
                "           redis.replicate_commands()\n" +
                "           cursor = tonumber(res[1])\n" +
                "           local ks = res[2]\n" +
                "           keynum = #ks\n" +
                "           for i=1,keynum,1 do\n" +
                "               local k = tostring(ks[i])\n" +
                "               delNum = delNum + redis.call('del', k)\n" +
                "            end\n" +
                "        end\n" +
                "  until (cursor <= 0)\n" +
                "\n" +
                "  return delNum\n" +
                "end\n" +
                "\n" +
                "local a = #KEYS\n" +
                "local b = 1\n" +
                "local total = 0\n" +
                "while (b <= a)\n" +
                "do\n" +
                "    total = total + scan(KEYS[b])\n" +
                "    b = b + 1\n" +
                "end\n" +
                "\n" +
                "return total";
        DefaultRedisScript<Long> redisScript = new DefaultRedisScript<>();
        redisScript.setResultType(Long.class);
        redisScript.setScriptText(luaScript1);
        Object execute = stringRedisTemplate.execute(redisScript, Collections.singletonList("MarketCache*"), "1000");
        log.info("删除缓存数量: {}", execute);
    }

    @Override
    public void deleteCacheByKey(String key) {
        if (StringUtils.isEmpty(key)) {
            throw new RuntimeException("缓存 key 不能为空");
        }
        if (!key.startsWith(CACHE_FLAG)) {
            throw new RuntimeException("缓存 key 的格式错误");
        }
        stringRedisTemplate.delete(key);
    }

    @Override
    public boolean hasKey(String key) {
        return Boolean.TRUE.equals(stringRedisTemplate.hasKey(key));
    }

    @Override
    public void setKey(String key, Object response, long cacheSeconds) {
        try {
            stringRedisTemplate.opsForValue().set(key, JSONUtil.toJsonStr(response), cacheSeconds, TimeUnit.SECONDS);
        } catch (Exception e) {
            log.error("IMarketCacheService.cacheResponse() failed!", e);
        }
    }
}
